package com.bird.设计模式.创建型.单例模式.枚举类型单例;

import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * @data 2022/2/28 12:09
 * @author: bird
 * @description: 枚举类-单例
 */
public class Test {

    // 枚举类 防止序列化破坏
    public static void main(String[] args) throws IOException, ClassNotFoundException {

        EnumInstance instance = EnumInstance.getInstance();
        //赋值
        instance.setData(new Object());
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("singleton_file"));
        oos.writeObject(instance);

        // 从文件中读取对象
        File file = new File("singleton_file");
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
        EnumInstance newInstance = (EnumInstance) ois.readObject();
        System.out.println(instance.getData());
        System.out.println(newInstance.getData());
        System.out.println(instance == newInstance);
        instance.printTest();

        /* 结论:枚举类型的单例可以防止序列化攻击.
           原因是:
           1: 通过String name = readString(false); 获取枚举类型的名称
           2: 通过Enum<?> en = Enum.valueOf((Class)cl, name); 通过枚举类型的名称获取枚举的实例
           3: 而且枚举类型的名称只有一个 所以只能实例化一个
           序列化是通过ObjectInputStream这个类实例实例化出枚举类。
         */
    }

    // 枚举类型的单例 防止反射攻击
    public static void main3(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Class objectClass = EnumInstance.class;
        Constructor constructor = objectClass.getDeclaredConstructor(String.class, int.class);
        constructor.setAccessible(true);
        EnumInstance instance = (EnumInstance) constructor.newInstance("奋斗的小鸟", 888);

        /*结论：不能通过反射创建枚举类的实例
         *原因是：
         *反射是通过Constructor的构造器来进行实例化。
         */

    }
}
